import PartnerContentLink from 'components/PartnerContentLink';
import Callout from 'components/Callout';
import {Tab, Tabs} from 'nextra-theme-docs';
import Details from 'components/Details';

# Global configuration

Configuration properties that you use across your Next.js app can be set globally.

## Client- and Server Components [#client-server-components]

Depending on if you handle [internationalization in Server- or Client Components](/docs/environments/server-client-components), the configuration from `i18n.ts` or `NextIntlClientProvider` will be applied respectively.

### `i18n.ts` & `getRequestConfig`

`i18n.ts` can be used to provide configuration for **Server Components** via the `getRequestConfig` function and should be set up based on wether you're using [i18n routing](/docs/getting-started/app-router) or not.

<Tabs items={['With i18n routing', 'Without i18n routing']}>

<Tab>

```tsx filename="i18n.ts"
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';

// Can be imported from a shared config
const locales = ['en', 'de'];

export default getRequestConfig(async ({locale}) => {
  // Validate that the incoming `locale` parameter is valid
  if (!locales.includes(locale as any)) notFound();

  return {
    messages: (await import(`../messages/${locale}.json`)).default
  };
});
```

</Tab>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async () => {
  // Provide a static locale, fetch a user setting,
  // read from `cookies()`, `headers()`, etc.
  const locale = 'en';

  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default
  };
});
```

</Tab>
</Tabs>

The configuration object is created once for each request by internally using React's [`cache`](https://react.dev/reference/react/cache). The first component to use internationalization will call the function defined with `getRequestConfig`.

Since this function is executed during the Server Components render pass, you can call functions like [`cookies()`](https://nextjs.org/docs/app/api-reference/functions/cookies) and [`headers()`](https://nextjs.org/docs/app/api-reference/functions/headers) to return configuration that is request-specific.

### `NextIntlClientProvider`

`NextIntlClientProvider` can be used to provide configuration for **Client Components**.

```tsx filename="layout.tsx" /NextIntlClientProvider/
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';

export default async function RootLayout(/* ... */) {
  // Providing all messages to the client
  // side is the easiest way to get started
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
```

These props are inherited if you're rendering `NextIntlClientProvider` from a Server Component:

1. `locale`
2. `now`
3. `timeZone`

In contrast, these props can be provided as necessary:

1. `messages` (see [Internationalization in Client Components](/docs/environments/server-client-components#using-internationalization-in-client-components))
2. `formats`
3. `defaultTranslationValues`
4. `onError` and `getMessageFallback`

<Details id="nextintlclientprovider-non-serializable-props">
<summary>How can I provide non-serializable props like `onError` to `NextIntlClientProvider`?</summary>

React limits the types of props that can be passed to Client Components to the ones that are [serializable](https://react.dev/reference/rsc/use-client#serializable-types). Since `onError`, `getMessageFallback` and `defaultTranslationValues` can receive functions, these configuration options can't be automatically inherited by the client side.

In order to define these values, you can wrap `NextIntlClientProvider` with another component that is marked with `'use client'` and defines the relevant props:

```tsx filename="IntlProvider.tsx"
'use client';

import {NextIntlClientProvider} from 'next-intl';

export default function IntlProvider({
  locale,
  now,
  timeZone,
  messages,
  formats
}) {
  return (
    <NextIntlClientProvider
      // Define non-serializable props here
      defaultTranslationValues={{
        i: (text) => <i>{text}</i>
      }}
      onError={(error) => console.error(error)}
      getMessageFallback={({namespace, key}) => `${namespace}.${key}`}
      // Make sure to forward these props to avoid markup mismatches
      locale={locale}
      now={now}
      timeZone={timeZone}
      // Provide as necessary
      messages={messages}
      formats={formats}
    />
  );
}
```

Once you have defined your client-side provider component, you can use it in a Server Component:

```tsx filename="layout.tsx"
import IntlProvider from './IntlProvider';
import {getLocale, getNow, getTimeZone, getMessages} from 'next-intl/server';

export default async function RootLayout({children}) {
  const locale = await getLocale();
  const now = await getNow();
  const timeZone = await getTimeZone();
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider
          locale={locale}
          now={now}
          timeZone={timeZone}
          messages={messages}
        >
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
```

By doing this, your provider component will already be part of the client-side bundle and can therefore define and pass functions as props.

**Important:** Be sure to pass explicit `locale`, `timeZone` and `now` props to `NextIntlClientProvider` in this case, since these aren't automatically inherited from a Server Component when you import `NextIntlClientProvider` from a Client Component.

</Details>

## Messages

The most crucial aspect of internationalization is providing labels based on the user's language. The recommended workflow is to store your messages in your repository along with the code.

```
├── messages
│   ├── en.json
│   ├── de-AT.json
│   └── ...
...
```

Colocating your messages with app code is beneficial because it allows developers to make changes quickly and additionally, you can use the shape of your local messages for [type checking](/docs/workflows/typescript). Translators can collaborate on messages by using CI tools, such as <PartnerContentLink name="localization-management-intro" href="https://store.crowdin.com/github">Crowdin's GitHub integration</PartnerContentLink>, which allows changes to be synchronized directly into your code repository.

That being said, `next-intl` is agnostic to how you store messages and allows you to freely define an async function that fetches them while your app renders:

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    messages: (await import(`../messages/${locale}.json`)).default
  };
});
```

After messages are configured, they can be used via [`useTranslations`](/docs/usage/messages#rendering-messages-with-usetranslations).

In case you require access to messages in a component, you can read them via `useMessages()` or `getMessages()` from your configuration:

```tsx
// Regular components
import {useMessages} from 'next-intl';
const messages = useMessages();

// Async Server Components
import {getMessages} from 'next-intl/server';
const messages = await getMessages();
```

</Tab>
<Tab>

```tsx
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';

async function Component({children}) {
  // Read messages configured via `i18n.ts`
  const messages = await getMessages();

  return (
    <NextIntlClientProvider messages={messages}>
      {children}
    </NextIntlClientProvider>
  );
}
```

</Tab>
</Tabs>

<Details id="messages-remote-sources">
<summary>How can I load messages from remote sources?</summary>

While it's recommended to colocate at least the messages for the default locale, you can also load messages from remote sources, e.g. with <PartnerContentLink name="localization-management-intro" href="https://crowdin.github.io/ota-client-js/">the Crowdin OTA JS Client</PartnerContentLink>.

```tsx
import OtaClient from '@crowdin/ota-client';

const defaultLocale = 'en';
const client = new OtaClient('<distribution-hash>');
const messages =
  locale === defaultLocale
    ? (await import(`../../messages/en.json`)).default
    : await client.getStringsByLocale(locale);
```

</Details>

<Details id="messages-fallback">
<summary>How can I use messages from another locale as fallbacks?</summary>

If you have incomplete messages for a given locale and would like to use messages from another locale as a fallback, you can merge the two accordingly.

```tsx
import deepmerge from 'deepmerge';

const userMessages = (await import(`../../messages/${locale}.json`)).default;
const defaultMessages = (await import(`../../messages/en.json`)).default;
const messages = deepmerge(defaultMessages, userMessages);
```

</Details>

<Details id="messages-split-files">
<summary>How can I split my messages into multiple files?</summary>

Since messages can be freely defined and loaded, you can split them into multiple files and merge them later at runtime if you prefer:

```tsx
const messages = {
  ...(await import(`../../messages/${locale}/login.json`)).default,
  ...(await import(`../../messages/${locale}/dashboard.json`)).default
};
```

Note that [the VSCode integration for `next-intl`](/docs/workflows/vscode-integration) can help you manage messages within a single, large file. If you're splitting messages purely for organizational reasons, you might want to consider using this instead.

</Details>

## Time zone

Specifying a time zone affects the rendering of dates and times. By default, the time zone of the server runtime will be used, but can be customized as necessary.

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    // The time zone can either be statically defined, read from the
    // user profile if you store such a setting, or based on dynamic
    // request information like the locale or a cookie.
    timeZone: 'Europe/Vienna'
  };
});
```

</Tab>
<Tab>

```tsx
// The time zone can either be statically defined, read from the
// user profile if you store such a setting, or based on dynamic
// request information like the locale or a cookie.
const timeZone = 'Europe/Vienna';

<NextIntlClientProvider timeZone={timeZone}>...<NextIntlClientProvider>
```

</Tab>
</Tabs>

The available time zone names can be looked up in [the tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).

The configured time zone can be read via `useTimeZone` or `getTimeZone` in components:

```tsx
// Regular components
import {useTimeZone} from 'next-intl';
const messages = useTimeZone();

// Async Server Components
import {getTimeZone} from 'next-intl/server';
const timeZone = await getTimeZone();
```

The time zone in Client Components is automatically inherited from the server
side if you wrap the relevant components in a `NextIntlClientProvider` that is
rendered by a Server Component. For all other cases, you can specify the value
explicitly on a wrapping `NextIntlClientProvider`.

## Now value [#now]

When formatting [relative dates and times](/docs/usage/dates-times#formatting-relative-time), `next-intl` will format times in relation to a reference point in time that is referred to as "now". By default, this is the time a component renders.

If you prefer to override the default, you can provide an explicit value for `now`:

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    // This is the default, a single date instance will be
    // used by all Server Components to ensure consistency.
    // Tip: This value can be mocked to a constant value
    // for consistent results in end-to-end-tests.
    now: new Date()
  };
});
```

</Tab>
<Tab>

```tsx
const now = new Date('2020-11-20T10:36:01.516Z');

<NextIntlClientProvider now={now}>...</NextIntlClientProvider>;
```

</Tab>
</Tabs>

The configured `now` value can be read in components via `useNow` or `getNow`:

```tsx
// Regular components
import {useNow} from 'next-intl';
const now = useNow();

// Async Server Components
import {getNow} from 'next-intl/server';
const now = await getNow();
```

Similarly to the `timeZone`, the `now` value in Client Components is
automatically inherited from the server side if you wrap the relevant
components in a `NextIntlClientProvider` that is rendered by a Server
Component.

## Formats

To achieve consistent date, time, number and list formatting, you can define a set of global formats.

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    formats: {
      dateTime: {
        short: {
          day: 'numeric',
          month: 'short',
          year: 'numeric'
        }
      },
      number: {
        precise: {
          maximumFractionDigits: 5
        }
      },
      list: {
        enumeration: {
          style: 'long',
          type: 'conjunction'
        }
      }
    }
  };
});
```

Note that `formats` are not automatically inherited by Client Components. If you want to make this available in Client Components, you should provide the same configuration to [`NextIntlClientProvider`](#nextintlclientprovider).

</Tab>
<Tab>

```tsx
<NextIntlClientProvider
  formats={{
    dateTime: {
      short: {
        day: 'numeric',
        month: 'short',
        year: 'numeric'
      }
    },
    number: {
      precise: {
        maximumFractionDigits: 5
      }
    },
    list: {
      enumeration: {
        style: 'long',
        type: 'conjunction'
      }
    }
  }}
>
  ...
</NextIntlClientProvider>
```

</Tab>
</Tabs>

Once you have `formats` set up, you can use them in your components via `useFormatter`:

```tsx
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();

  format.dateTime(new Date('2020-11-20T10:36:01.516Z'), 'short');
  format.number(47.414329182, 'precise');
  format.list(['HTML', 'CSS', 'JavaScript'], 'enumeration');
}
```

Global formats for numbers, dates and times can be referenced in messages too:

```json filename="en.json"
{
  "ordered": "You've ordered this product on {orderDate, date, short}",
  "latitude": "Latitude: {latitude, number, precise}"
}
```

```tsx
import {useTranslations} from 'next-intl';

function Component() {
  const t = useTranslations();

  t('ordered', {orderDate: new Date('2020-11-20T10:36:01.516Z')});
  t('latitude', {latitude: 47.414329182});
}
```

## Default translation values

To achieve consistent usage of translation values and reduce redundancy, you can define a set of global default values. This configuration can also be used to apply consistent styling of commonly used rich text elements.

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.tsx"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    defaultTranslationValues: {
      important: (chunks) => <b>{chunks}</b>,
      value: 123
    }
  };
});
```

Note that `defaultTranslationValues` are not automatically inherited by Client Components. If you want to make this available in Client Components, you should provide the same configuration to [`NextIntlClientProvider`](#nextintlclientprovider).

</Tab>
<Tab>

```tsx
<NextIntlClientProvider
  defaultTranslationValues={{
    important: (chunks) => <b>{chunks}</b>,
    value: 123
  }}
>
  ...
</NextIntlClientProvider>
```

Note that `NextIntlClientProvider` is a Client Component, therefore if you render it from a Server Component, the props need to be serializable across the server/client boundary (see: [How can I provide non-serializable props to `NextIntlClientProvider`](#nextintlclientprovider-non-serializable-props)).

</Tab>
</Tabs>

## Error handling (`onError` & `getMessageFallback`) [#error-handling]

By default, when a message fails to resolve or when the formatting failed, an error will be printed on the console. In this case `${namespace}.${key}` will be rendered instead to keep your app running.

This behavior can be customized with the `onError` and `getMessageFallback` configuration option.

<Tabs items={['i18n.ts', 'Provider']}>
<Tab>

```tsx filename="i18n.ts"
import {getRequestConfig} from 'next-intl/server';
import {IntlErrorCode} from 'next-intl';

export default getRequestConfig(async ({locale}) => {
  // ...

  return {
    onError(error) {
      if (error.code === IntlErrorCode.MISSING_MESSAGE) {
        // Missing translations are expected and should only log an error
        console.error(error);
      } else {
        // Other errors indicate a bug in the app and should be reported
        reportToErrorTracking(error);
      }
    },
    getMessageFallback({namespace, key, error}) {
      const path = [namespace, key].filter((part) => part != null).join('.');

      if (error.code === IntlErrorCode.MISSING_MESSAGE) {
        return path + ' is not yet translated';
      } else {
        return 'Dear developer, please fix this message: ' + path;
      }
    }
  };
});
```

Note that `onError` and `getMessageFallback` are not automatically inherited by Client Components. If you want to make this functionality available in Client Components, you should provide the same configuration to [`NextIntlClientProvider`](#nextintlclientprovider).

</Tab>
<Tab>

```tsx
import {NextIntlClientProvider, IntlErrorCode} from 'next-intl';

function onError(error) {
  if (error.code === IntlErrorCode.MISSING_MESSAGE) {
    // Missing translations are expected and should only log an error
    console.error(error);
  } else {
    // Other errors indicate a bug in the app and should be reported
    reportToErrorTracking(error);
  }
}

function getMessageFallback({namespace, key, error}) {
  const path = [namespace, key].filter((part) => part != null).join('.');

  if (error.code === IntlErrorCode.MISSING_MESSAGE) {
    return path + ' is not yet translated';
  } else {
    return 'Dear developer, please fix this message: ' + path;
  }
}

<NextIntlClientProvider
  onError={onError}
  getMessageFallback={getMessageFallback}
>
  ...
</NextIntlClientProvider>;
```

</Tab>
</Tabs>

## Locale

The current locale of your app is automatically incorporated into hooks like `useTranslations` & `useFormatter` and will affect the rendered output.

In case you need to use this value in other places of your app, e.g. to implement a locale switcher or to pass it to API calls, you can read it via `useLocale` or `getLocale`:

```tsx
// Regular components
import {useLocale} from 'next-intl';
const locale = useLocale();

// Async Server Components
import {getLocale} from 'next-intl/server';
const locale = await getLocale();
```

<Details id="locale-change">
<summary>How can I change the locale?</summary>

Depending on if you're using [i18n routing](/docs/getting-started/app-router), the locale can be changed as follows:

1. **With i18n routing**: The locale is managed by the router and can be changed by using navigation APIs from `next-intl` like [`Link`](/docs/routing/navigation#link) or [`useRouter`](/docs/routing/navigation#userouter).
2. **Without i18n routing**: You can change the locale by updating the value where the locale is read from (e.g. a cookie, a user setting, etc.). If you're looking for inspiration, you can have a look at the [App Router without i18n routing example](/examples#app-router-without-i18n-routing) that manages the locale via a cookie.

</Details>

<Details id="locale-return-value">
<summary>Which value is returned from `useLocale`?</summary>

The returned value is resolved based on these priorities:

1. **Server Components**: If you're using [i18n routing](/docs/getting-started/app-router), the returned locale is the one that you've either provided via [`unstable_setRequestLocale`](/docs/getting-started/app-router/with-i18n-routing#static-rendering) or alternatively the one in the `[locale]` segment that was matched by the middleware. If you're not using i18n routing, the returned locale is the one that you've provided via `getRequestConfig`.
2. **Client Components**: In this case, the locale is received from `NextIntlClientProvider` or alternatively `useParams().locale`. Note that `NextIntlClientProvider` automatically inherits the locale if the component is rendered by a Server Component. For all other cases, you can specify the value
   explicitly.

</Details>

<Details id="locale-pages-router">
<summary>I'm using the Pages Router, how can I access the locale?</summary>

If you use [internationalized routing with the Pages Router](https://nextjs.org/docs/pages/building-your-application/routing/internationalization), you can receive the locale from the router in order to pass it to `NextIntlClientProvider`:

```tsx filename="_app.tsx"
import {useRouter} from 'next/router';

// ...

const router = useRouter();

return (
  <NextIntlClientProvider locale={router.locale}>
    ...
  </NextIntlClientProvider>;
);
```

</Details>
